import AppConfig from '@/appConfig'
import {BaseLayerType, LayerCatetory, LayerType} from './EarthConstant'
import '../plugin/ArcGisMapServerImageryProvider'
import '../plugin/ArcGisImageServerImageryProvider'
import '../plugin/VTileImageryProvider'

/**
 * 地球初始化
 * @param containerId 容器
 * @param sceneMode   场景模式
 * @param baseLayerName 底图名字
 * @param labelLayerShow 是否显示label图层
 * @param boundaryLayerShow 是否显示边界图层
 * @returns {Viewer|Viewer}
 */
const init = (containerId, sceneMode) => {
  let chinaRect = AppConfig.MAP.chinaExtent;
  Cesium.Camera.DEFAULT_VIEW_RECTANGLE = new Cesium.Rectangle.fromDegrees(chinaRect[0], chinaRect[1], chinaRect[2], chinaRect[3]);

  let skyBox = new Cesium.SkyBox({
    sources: {
      positiveX: './assets/images/skybox/posx.jpg',
      negativeX: './assets/images/skybox/negx.jpg',
      positiveY: './assets/images/skybox/posy.jpg',
      negativeY: './assets/images/skybox/negy.jpg',
      positiveZ: './assets/images/skybox/posz.jpg',
      negativeZ: './assets/images/skybox/negz.jpg'
    }
  });


  let viewer = new Cesium.Viewer(containerId, {
    shouldAnimate: true,
    animation: true,
    infoBox: true,
    selectionIndicator: true,
    geocoder: false,
    fullscreenButton: false,
    timeline: true,
    sceneModePicker: true,
    navigationHelpButton: false,
    baseLayerPicker: false,
    homeButton: true,
    sceneMode: sceneMode || Cesium.SceneMode.SCENE3D,
    // mapProjection: new Cesium.WebMercatorProjection(),
    skyBox: skyBox,
    imageryProvider: defImgProvider(),
    // terrainProvider: defTerrainProvider(),
    orderIndependentTranslucency: true,
    // contextOptions: {
    //     webgl: {
    //         alpha: true,
    //     }
    // }
  });

  //背景透明 需配合webgl的aplpha
  // viewer._cesiumWidget._creditContainer.style.display = "none";

  let scene = viewer.scene;
  let globe = scene.globe;
  // scene.skyBox.show = false;
  // scene.backgroundColor = new Cesium.Color(0.0, 0.0, 0.0, 0.0);
  scene.fog.enabled = true;
  globe.showGroundAtmosphere = true; //大气层
  globe.enableLighting = true; //昼夜

  //防钻地
  viewer.clock.onTick.addEventListener(function () {
    let camera = viewer.camera;
    let pitch = camera.pitch;
    let heading = camera.heading;
    let roll = camera.roll;
    let sceneMode = viewer.sceneMode;
    if (sceneMode == Cesium.SceneMode.SCENE3D) {
      if (pitch > -0.15) {
        viewer.scene.screenSpaceCameraController.enableTilt = false;
        camera.setView({
          orientation: {
            heading: heading,  // Cesium.Math.toRadians(dHeading),
            pitch: -0.15,    // Cesium.Math.toRadians(-15),
            roll: roll       // Cesium.Math.toRadians(dRoll)
          }
        });
      } else {
        viewer.scene.screenSpaceCameraController.enableTilt = true;
      }
    }
  });

  return viewer;
}


/**
 * 默认的底图服务
 */
const defImgProvider = () => {
  let url = './assets/img/world.jpg';
  let lyr = createImgLayer({url})
  return lyr;
};


/**
 * 默认的地形服务
 */
const defTerrainProvider = () => {
  let url = AppConfig.TerrainUrl;
  if (url) {
    return new Cesium.CesiumTerrainProvider({url});
  } else {
    return null;
  }
};

/**
 * 加载底图
 * @param viewer
 * @param baseName 底图分组名称
 * @param labelLayerShow 是否显示注记图层
 * @param boundaryLayerShow 是否显示边界图层
 */
const addBaseLayers = (viewer, baseLayerName, labelLayerShow, boundaryLayerShow) => {
  removeBaseLayers(viewer);

  let labelOpacity = 1, boundaryOpactiy = 1;
  if (labelLayerShow === false) {
    labelOpacity = 0;
  }
  if (boundaryLayerShow === false) {
    boundaryOpactiy = 0;
  }

  let BaseLayer = ConfigTools.getBaseByName(baseLayerName, AppConfig.BaseLayers);
  let baseLayerConfig = ConfigTools.getLayerById(BaseLayer.base, AppConfig.Layers);
  let labelLayerConfig = ConfigTools.getLayerById(BaseLayer.label, AppConfig.Layers);
  let boundaryLayerConfig = ConfigTools.getLayerById(BaseLayer.boundary, AppConfig.Layers);


  let baseLayer = addLayer(baseLayerConfig.params, {
    id: 'base',
    type: baseLayerConfig.type,
    catalog: LayerCatetory.BASE
  }, viewer);
  // let labelLayer = addLayer(labelLayerConfig.params, {
  //   id: 'label',
  //   type: labelLayerConfig.type,
  //   catalog: LayerCatetory.LABEL
  // }, viewer);
  // let boundaryLayer = addLayer(boundaryLayerConfig.params, {
  //   id: 'boundary',
  //   type: boundaryLayerConfig.type,
  //   catalog: LayerCatetory.BOUNDARY
  // }, viewer);

  //透明度
  // labelLayer.alpha = labelOpacity;
  // boundaryLayer.alpha = boundaryOpactiy;


  viewer.imageryLayers.lowerToBottom(baseLayer);
  let rootLyr = null;
  let imgLayers = viewer.imageryLayers._layers;
  for (let i = 0; i < imgLayers.length; i++) {
    let ly = imgLayers[i];
    if (typeof ly.catalog == 'undefined') {
      rootLyr = ly;
    }
  }
  if (rootLyr) {
    viewer.imageryLayers.lowerToBottom(rootLyr);
  }

  //注记与边界置顶
  raiseStaticLayer(viewer);
}


/**
 * 移除底图服务
 */
const removeBaseLayers = (viewer) => {
  let imageryLayers = viewer.imageryLayers;
  let imgLayers = imageryLayers._layers;

  let needremove = [];
  for (let i = 0; i < imgLayers.length; i++) {
    let ly = imgLayers[i];
    let catalog = ly.catalog;
    if (typeof catalog != 'undefined' && (catalog == LayerCatetory.BASE || catalog === LayerCatetory.LABEL || catalog == LayerCatetory.BOUNDARY)) {
      needremove.push(ly);
    }
  }
  for (let i = 0; i < needremove.length; i++) {
    imageryLayers.remove(needremove[i]);
  }
}


/**
 * 添加服务图层
 */
const addLayer = (param, options, viewer) => {
  let type = options.type;

  let lyr = null;
  switch (type) {
    case LayerType.WMTS:
      lyr = createWMTSLayer(param);
      break;
    case LayerType.WMS:
      lyr = createWmsLayer(param);
      break;
    case LayerType.XYZ:
      lyr = createXYZLayer(param);
      break;
    case LayerType.MAPSERVER:
    case "MAPSERVER":
      lyr = createArcgisMapLayer(param);
      break;
    case LayerType.IMAGESERVER:
    case "IMAGESERVER":
      lyr = createArcgisImageLayer(param);
      break;
    case LayerType.VTILE:
    case "VTILE":
      lyr = createVTileLayer(param);
      break;
    case LayerType.D3TILES:
      add3DTiles(param, options, viewer);
      break;
    case 'debug':
      lyr = createDebugerLayer(param)
  }

  if (lyr) {
    let imageryLayers = viewer.imageryLayers;
    let lyrprivider = imageryLayers.addImageryProvider(lyr, options.index);
    Object.assign(lyrprivider, options);
    raiseStaticLayer(viewer);
    return lyrprivider
  }

  return null;
}


/**
 * WMTS
 * @param url
 * @param layerName
 * @param params
 * @param viewer
 * @returns {*}
 */
const createWMTSLayer = (param) => {
  let tilingScheme = new Cesium.GeographicTilingScheme({
    numberOfLevelZeroTilesX: param.ZeroTilesX,
    numberOfLevelZeroTilesY: param.ZeroTilesY
  })
  if (param.srid && (param.srid.indexOf('3857') != -1 || param.srid.indexOf('3785') != -1 || param.srid.indexOf('900913') != -1)) {
    tilingScheme = new Cesium.WebMercatorTilingScheme({
      numberOfLevelZeroTilesX: param.ZeroTilesX,
      numberOfLevelZeroTilesY: param.ZeroTilesY
    })
  }

  let defParam = {
    tilingScheme: tilingScheme
  };

  let lyr = new Cesium.WebMapTileServiceImageryProvider({...defParam, ...param});
  return lyr;
}

/**
 * arcgis MapServer图层
 * @param url
 * @param viewer
 * @param index   layerindex
 * @returns {ImageryLayer}
 */
const createArcgisMapLayer = (param) => {
  let defParam = {
    enablePickFeatures: true,
    usePreCachedTilesIfAvailable: true
  }
  let lyr = new Cesium.ArcGisMapServerImageryProvider2({...defParam, ...param});
  return lyr;
}

/**
 * arcgis ImageServer图层
 * @param url
 * @param viewer
 * @returns {ImageryLayer}
 */
const createArcgisImageLayer = (param) => {
  let defParam = {
    enablePickFeatures: true,
    usePreCachedTilesIfAvailable: true
  }
  let lyr = new Cesium.ArcGisImageServerImageryProvider({...defParam, ...param})
  return lyr;
}

/**
 * 矢量瓦片图层
 * @param url
 * @param viewer
 * @returns {ImageryLayer}
 */
const createVTileLayer = (param) => {
  let defParam = {
    tilingScheme: new Cesium.GeographicTilingScheme(),
    tileWidth: 512,
    tileHeight: 512,
    customTags: {
      l: function (imageryProvider, x, y, level) {
        return level + 2
      }
    }
  };
  let lyr = new Cesium.UrlTemplateImageryProvider({...defParam, ...param})
  return lyr;
}

/**
 * wms图层
 * @param url
 * @param layerName
 * @param params
 * @param viewer
 * @returns {ImageryLayer}
 */
const createWmsLayer = (param) => {
  let lyr = new Cesium.WebMapServiceImageryProvider(param);
  return lyr;
}


/**
 * xyz图层
 * @param url
 * @param viewer
 * @returns {ImageryLayer}
 */
const createXYZLayer = (param) => {
  let lyr = new Cesium.UrlTemplateImageryProvider(param)
  return lyr;
}

/**
 * 静态图片图层
 * @param url
 * @param viewer
 */
const createImgLayer = (param) => {
  let lyr = new Cesium.SingleTileImageryProvider(param);
  return lyr;
}


/**
 * 3DTiles
 * @param url
 * @param viewer
 */
const add3DTiles = (url, viewer) => {
  let tileset = new Cesium.Cesium3DTileset({
    url: url
  });
  tileset.readyPromise.then((tileset) => {
    viewer.scene.primitives.add(tileset);
    viewer.zoomTo(tileset, new Cesium.HeadingPitchRange(0.0, -0.5, tileset.boundingSphere.radius * 2.0));
    let height = 0;
    let cartographic = Cesium.Cartographic.fromCartesian(tileset.boundingSphere.center);
    let surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, cartographic.height);
    let offset = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, height);
    let translation = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3());
    tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
  }).otherwise(function (error) {
    console.log(error);
  });

  return tileset;
}

const createDebugerLayer = (param) => {
  return new Cesium.TileCoordinatesImageryProvider(param)
}


/**
 * 置顶图层
 * @param viewer
 */
const raiseStaticLayer = (viewer) => {
  let imageryLayers = viewer.imageryLayers;
  let imgLayers = imageryLayers._layers;
  for (let i = 0; i < imgLayers.length; i++) { //边界与注记图层置顶
    let ly = imgLayers[i];
    let catalog = ly.catalog;
    if (typeof catalog != 'undefined' && catalog == LayerCatetory.LABEL || catalog == LayerCatetory.BOUNDARY) {
      imageryLayers.raiseToTop(ly);
    }
  }
}


/**
 * 根据高度计算级别
 * @param height
 * @returns {number}
 */
const getLevelByHeight = (height) => {
  let A = 40487.57;
  let B = 0.00007096758;
  let C = 91610.74;
  let D = -40467.74;
  return Math.round(D + (A - D) / (1 + Math.pow(height / C, B))) + 1;
}

/**
 * 获取状态参数
 * @param viewer
 * @returns {{}}
 */
const getStatusParam = (viewer) => {
  let camera = viewer.camera;
  let scene = viewer.scene;
  let canvas = scene.canvas;
  let globe = scene.globe;
  let ellipsoid = globe.ellipsoid;


  let result = {};

  let height = Math.ceil(camera.positionCartographic.height);
  let mapLevel = getLevelByHeight(height);

  let regionLevel = 0;
  let zoomLevels = AppConfig.MAP.ZoomLevels;
  for (let i = 0; i < zoomLevels.length; i++) {
    let one = zoomLevels[i];
    let h = one.height;
    if (height > h) {
      regionLevel = one.level;
      break;
    }
  }


  result.height = height;
  result.mapLevel = mapLevel;
  result.mapRegionLevel = regionLevel; //地图区域级别


  let canvasCenter = new Cesium.Cartesian2(canvas.clientWidth / 2.0, canvas.clientHeight / 2.0);
  let cartesian = viewer.camera.pickEllipsoid(canvasCenter, ellipsoid);
  if (Cesium.defined(cartesian)) {
    //将笛卡尔坐标转换为地理坐标
    let cartographic = ellipsoid.cartesianToCartographic(cartesian);
    let longitude = Cesium.Math.toDegrees(cartographic.longitude);
    let latitude = Cesium.Math.toDegrees(cartographic.latitude);
    let lonlat = {lon: longitude, lat: latitude};
    result.center = lonlat;
  }

  let rect = camera.computeViewRectangle(ellipsoid);

  if (rect) {
    result.rect = rect;
    let center = Cesium.Rectangle.center(rect);
    let rect_lonlat = {};
    rect_lonlat.west = Cesium.Math.toDegrees(rect.west);
    rect_lonlat.south = Cesium.Math.toDegrees(rect.south);
    rect_lonlat.east = Cesium.Math.toDegrees(rect.east);
    rect_lonlat.north = Cesium.Math.toDegrees(rect.north);
    rect_lonlat.center = {lon: Cesium.Math.toDegrees(center.longitude), lat: Cesium.Math.toDegrees(center.latitude)};
    result.rect_lonlat = rect_lonlat;
  }


  return result;
}


/**
 * 位置解析
 * @param cartesian2 屏幕坐标
 * @param camera
 * @param ellipsoid
 */
const parsePosition = (cartesian2, viewer) => {
  let camera = viewer.camera;
  let scene = viewer.scene;
  let globe = scene.globe;
  let ellipsoid = globe.ellipsoid;

  let height = Math.ceil(camera.positionCartographic.height);
  let mapLevel = getLevelByHeight(height);

  // let ray = camera.getPickRay(cartesian2);
  // let cartesian3 = globe.pick(ray, scene);
  let  cartesian3 = viewer.camera.pickEllipsoid(cartesian2, ellipsoid);

  if (cartesian3) {
    //经纬度的弧度表示
    let cartographic = ellipsoid.cartesianToCartographic(cartesian3);
    let longitude = Cesium.Math.toDegrees(cartographic.longitude);
    let latitude = Cesium.Math.toDegrees(cartographic.latitude);
    let lonlat = {lon: longitude, lat: latitude};
    return {cartesian2, cartesian3, cartographic, lonlat,mapLevel};
  }
  return null;
}


/**
 * 配置文件数据获取工具
 */
const ConfigTools = {
  /**
   * 根据底图名称获取底图组
   * @param name
   * @returns {*}
   */
  getBaseByName: (name, arr) => {
    for (let i = 0; i < arr.length; i++) {
      let one = arr[i];
      if (one.name == name) {
        return one;
      }
    }
    return arr[0];
  },

  /**
   * 根据id获取图层服务配置
   * @param id
   * @returns {null|*}
   */
  getLayerById: (id, layers) => {
    for (let i = 0; i < layers.length; i++) {
      let one = layers[i];
      if (one.id == id) {
        return one;
      }
    }
    return null;
  }
};


export default {
  init, addBaseLayers, addLayer, getLevelByHeight, parsePosition, getStatusParam
}
